from typing import List, Dict, Any, Optional
from fastapi import HTTPException
from sqlalchemy.orm import Session, joinedload

from app.models.mcp_tool import MCPCategory, MCPTool, MCPSubscription
from app.schemas.mcp_tool import MCPCategoryCreate, MCPCategoryUpdate, MCPToolCreate, MCPToolUpdate


class MCPCategoryService:
    @staticmethod
    def get_categories(db: Session) -> List[MCPCategory]:
        return db.query(MCPCategory).all()
    
    @staticmethod
    def get_category(db: Session, category_id: int) -> MCPCategory:
        category = db.query(MCPCategory).filter(MCPCategory.id == category_id).first()
        if not category:
            raise HTTPException(status_code=404, detail="分类不存在")
        return category
    
    @staticmethod
    def create_category(db: Session, category: MCPCategoryCreate) -> MCPCategory:
        db_category = MCPCategory(**category.dict())
        db.add(db_category)
        db.commit()
        db.refresh(db_category)
        return db_category
    
    @staticmethod
    def update_category(db: Session, category_id: int, category: MCPCategoryUpdate) -> MCPCategory:
        db_category = MCPCategoryService.get_category(db, category_id)
        
        update_data = category.dict(exclude_unset=True)
        for key, value in update_data.items():
            setattr(db_category, key, value)
        
        db.commit()
        db.refresh(db_category)
        return db_category
    
    @staticmethod
    def delete_category(db: Session, category_id: int) -> None:
        db_category = MCPCategoryService.get_category(db, category_id)
        
        # 检查该分类下是否有工具
        tools_count = db.query(MCPTool).filter(MCPTool.category_id == category_id).count()
        if tools_count > 0:
            raise HTTPException(status_code=400, detail="该分类下有工具，无法删除")
        
        db.delete(db_category)
        db.commit()


class MCPToolService:
    @staticmethod
    def get_tools(db: Session, skip: int = 0, limit: int = 100) -> List[MCPTool]:
        return db.query(MCPTool).options(joinedload(MCPTool.category)).offset(skip).limit(limit).all()
    
    @staticmethod
    def get_tools_by_category(db: Session, category_id: int) -> List[MCPTool]:
        return db.query(MCPTool).filter(MCPTool.category_id == category_id).all()
    
    @staticmethod
    def get_tool(db: Session, tool_id: int) -> MCPTool:
        tool = db.query(MCPTool).options(joinedload(MCPTool.category)).filter(MCPTool.id == tool_id).first()
        if not tool:
            raise HTTPException(status_code=404, detail="工具不存在")
        return tool
    
    @staticmethod
    def get_tool_by_english_name(db: Session, english_name: str) -> MCPTool:
        tool = db.query(MCPTool).options(joinedload(MCPTool.category)).filter(MCPTool.english_name == english_name).first()
        if not tool:
            raise HTTPException(status_code=404, detail="工具不存在")
        return tool
    
    @staticmethod
    def create_tool(db: Session, tool: MCPToolCreate) -> MCPTool:
        # 确认分类存在
        category = db.query(MCPCategory).filter(MCPCategory.id == tool.category_id).first()
        if not category:
            raise HTTPException(status_code=404, detail="分类不存在")
        
        db_tool = MCPTool(**tool.dict())
        db.add(db_tool)
        db.commit()
        db.refresh(db_tool)
        return db_tool
    
    @staticmethod
    def update_tool(db: Session, tool_id: int, tool: MCPToolUpdate) -> MCPTool:
        db_tool = MCPToolService.get_tool(db, tool_id)
        
        update_data = tool.dict(exclude_unset=True)
        
        # 确认分类存在
        if "category_id" in update_data and update_data["category_id"]:
            category = db.query(MCPCategory).filter(MCPCategory.id == update_data["category_id"]).first()
            if not category:
                raise HTTPException(status_code=404, detail="分类不存在")
        
        for key, value in update_data.items():
            setattr(db_tool, key, value)
        
        db.commit()
        db.refresh(db_tool)
        return db_tool
    
    @staticmethod
    def delete_tool(db: Session, tool_id: int) -> None:
        db_tool = MCPToolService.get_tool(db, tool_id)
        
        # 检查是否有订阅
        subscriptions_count = db.query(MCPSubscription).filter(MCPSubscription.tool_id == tool_id).count()
        if subscriptions_count > 0:
            raise HTTPException(status_code=400, detail="该工具有订阅，无法删除")
        
        db.delete(db_tool)
        db.commit()
    
    @staticmethod
    def run_tool(db: Session, tool_id: int, parameters: Dict[str, Any]) -> Dict[str, Any]:
        """
        运行工具并返回结果
        这里只是一个示例实现，实际项目中应该调用相应的API或服务
        """
        tool = MCPToolService.get_tool(db, tool_id)
        
        # 确认工具处于激活状态
        if not tool.is_active:
            raise HTTPException(status_code=400, detail="工具未激活")
        
        # 示例实现，根据工具类型返回不同的结果
        if tool.english_name == "text2image":
            return {
                "result": {
                    "images": [
                        {
                            "url": "https://example.com/image1.png",
                            "width": 512,
                            "height": 512
                        }
                    ]
                }
            }
        elif tool.english_name == "web_search":
            return {
                "result": {
                    "items": [
                        {
                            "title": "搜索结果1",
                            "url": "https://example.com/result1",
                            "snippet": "这是搜索结果的摘要..."
                        }
                    ]
                }
            }
        else:
            return {
                "result": {
                    "message": f"工具 {tool.name} 运行成功"
                }
            }


class MCPSubscriptionService:
    @staticmethod
    def get_subscriptions(db: Session, user_id: Optional[int] = None, skip: int = 0, limit: int = 100) -> List[MCPSubscription]:
        query = db.query(MCPSubscription).options(joinedload(MCPSubscription.tool))
        
        if user_id is not None:
            query = query.filter(MCPSubscription.user_id == user_id)
        
        return query.offset(skip).limit(limit).all()
    
    @staticmethod
    def get_subscription(db: Session, subscription_id: int) -> MCPSubscription:
        subscription = db.query(MCPSubscription).options(joinedload(MCPSubscription.tool)).filter(MCPSubscription.id == subscription_id).first()
        if not subscription:
            raise HTTPException(status_code=404, detail="订阅不存在")
        return subscription
    
    @staticmethod
    def get_user_tool_subscription(db: Session, user_id: int, tool_id: int) -> Optional[MCPSubscription]:
        return db.query(MCPSubscription).filter(
            MCPSubscription.user_id == user_id,
            MCPSubscription.tool_id == tool_id
        ).first()
    
    @staticmethod
    def create_subscription(db: Session, user_id: int, tool_id: int) -> MCPSubscription:
        # 检查工具是否存在
        tool = db.query(MCPTool).filter(MCPTool.id == tool_id).first()
        if not tool:
            raise HTTPException(status_code=404, detail="工具不存在")
        
        # 检查用户是否已订阅
        existing = MCPSubscriptionService.get_user_tool_subscription(db, user_id, tool_id)
        if existing:
            if existing.is_active:
                raise HTTPException(status_code=400, detail="用户已订阅该工具")
            else:
                # 重新激活已存在的订阅
                existing.is_active = True
                db.commit()
                db.refresh(existing)
                return existing
        
        # 创建新订阅
        subscription = MCPSubscription(
            user_id=user_id,
            tool_id=tool_id,
            is_active=True
        )
        db.add(subscription)
        db.commit()
        db.refresh(subscription)
        return subscription
    
    @staticmethod
    def cancel_subscription(db: Session, user_id: int, tool_id: int) -> None:
        subscription = MCPSubscriptionService.get_user_tool_subscription(db, user_id, tool_id)
        if not subscription:
            raise HTTPException(status_code=404, detail="订阅不存在")
        
        subscription.is_active = False
        db.commit() 